﻿#pragma once
#if defined(_MSC_VER)
	#define _CRT_SECURE_NO_WARNINGS
	#pragma warning(disable:4996)
#endif
#include <iostream>
#include <array>
#include <vector>

namespace self {
	template<typename Ty, size_t Len>
	class MyArray
	{ // 栈区数据，不需要移动语义
	private:
		Ty m_data[Len]; // 数组元素
	public:
		MyArray()
			: m_data() {
		}; // 默认构造函数

		auto begin() { // 迭代器
			return m_data;
		}

		auto end() {
			return m_data + Len;
		}

		~MyArray() { // 析构函数
			printf("MyArray destructor callstd::endl.\n");
		}

		Ty& operator[](const size_t index) { // 下标运算符
			if (index >= Len)
				throw std::out_of_range("Index out of range."); // 越界检查，抛出异常
			return m_data[index];
		}

		const Ty& operator[](const size_t index) const { // 常量下标运算符
			if (index >= Len)
				throw std::out_of_range("Index out of range."); // 越界检查，抛出异常
			return m_data[index];
		}

		constexpr size_t my_size() const noexcept { // 获取数组大小
			return Len; // constexpr 修饰，表示允许在编译期间进行计算
		}

		Ty* get_data() { // 获取数组元素
			return m_data;
		}
	};


	template<typename Ty>
	class MyVector
	{
	private:
		Ty* m_data = nullptr; // 堆区数据，需要移动语义
		size_t m_len = 0; // 实际数组长度
		size_t m_capacity = 0; // 当前数组容量

		void allocate(size_t new_capacity) { // 申请内存，复制/移动数据
			if (new_capacity <= m_len)
				m_len = new_capacity; // 容量变小
			//Ty* new_data = new Ty[new_capacity]; // 申请新内存
			Ty* new_data = (Ty*)::operator new[](new_capacity * sizeof(Ty)); // malloc 申请新内存
			if (m_data) // 原有内存不为空，需要移动数据
				for (size_t i = 0; i < m_len; ++i)
					new_data[i] = std::move(m_data[i]); // 移动语义，将原有数据转移到新内存
			//delete[] m_data; // 释放原有内存
			for (size_t i = 0; i < m_len; ++i)
				if (m_data)
					m_data[i].~Ty(); // 调用元素的析构函数
			::operator delete(m_data, m_capacity * sizeof(Ty)); // free 释放指定大小的内存
			m_data = new_data; // 指向新内存
			m_capacity = new_capacity; // 更新容量
		}
	public:
		MyVector() { allocate(2); }
		~MyVector() { // 析构函数
			//delete[] m_data; // 释放内存
			//clean_data(); // 调用清理函数
			::operator delete(m_data, m_capacity * sizeof(Ty)); // free 释放指定大小的内存
			printf("MyVector destructor called.\n");
		}

		void add_end(const Ty& val) { // 复制到尾部
			if (m_len >= m_capacity)// 扩容
				allocate(m_capacity + m_capacity / 2); // 申请最多 1.5 倍容量
			m_data[m_len++] = val;
		}

		void move_end(Ty&& val) { // 移动到尾部
			if (m_len >= m_capacity) // 扩容
				allocate(m_capacity + m_capacity / 2);
			m_data[m_len++] = (Ty&&)val; // 移动语义，将原有数据转移到新内存
		}

		template<typename... Args>
		Ty& emplace_end(Args&&... args) { // 模仿实现 emplace_back 函数模板
			if (m_len >= m_capacity) // 扩容
				allocate(m_capacity + m_capacity / 2);
			//m_data[m_len] = Ty(std::forward<Args>(args)...); // 栈区构造元素，会进行拷贝
			new(&m_data[m_len]) Ty(std::forward<Args>(args)...); // 堆区构造元素，不进行拷贝，注意语法
			return m_data[m_len++]; // 返回新元素的引用
		}

		Ty pop_end() { // 删除尾部元素
			if (m_len > 0) {
				--m_len;
				Ty ret = std::move(m_data[m_len]); // 移动语义，将尾部元素转移到栈区
				m_data[m_len].~Ty(); // 调用元素的析构函数，实际长度减 1
				return ret;
			}
			else {
				Ty ret;
				return ret;
			}
		}

		void clean_data() { // 说明清理只能针对数据，不包括内存（m_data 的堆内存不能释放，不然会多次释放同一块内存）
			for (size_t i = 0; i < m_len; ++i)
				m_data[i].~Ty(); // 调用元素的析构函数
			/*delete m_data;
			m_data = nullptr; // 指向 nullptr
			m_capacity = 0; // 容量清零 */
			m_len = 0; // 实际长度清零
		}

		constexpr size_t get_len() const noexcept { return m_len; }

		Ty*& get_data() { // 获取数组，右值引用，转移所有权
			return this->m_data;
		}

		Ty& operator[](size_t index) const { // 下标运算符
			if (index >= m_len)
				throw std::out_of_range("Index out of range."); // 越界检查，抛出异常
			return m_data[index];
		}

		auto begin() { // 迭代器
			return m_data;
		}

		Ty* end() { // 迭代器
			return m_data + m_len;
		}
	};


	typedef struct Coordinates {
		float x = 0.0f, y = 0.0f, z = 0.0f;
		float* arr = new float[3];

		Coordinates() { arr[0] = 0.0f; arr[1] = 0.0f; arr[2] = 0.0f; }
		Coordinates(float scalar)
			: x(scalar), y(scalar), z(scalar) {
			arr[0] = scalar; arr[1] = scalar; arr[2] = scalar;
		}
		Coordinates(float a, float b, float c)
			: x(a), y(b), z(c) {
			arr[0] = a; arr[1] = b; arr[2] = c;
		}
		Coordinates(const Coordinates& other)
			: x(other.x), y(other.y), z(other.z) { // 复制构造函数
			std::cout << "Coordinates 拷贝构造函数被调用\n";
		}

		Coordinates& operator=(const Coordinates& other) { // 复制赋值运算符
			if (this == &other)
				return *this;
			x = other.x;
			y = other.y;
			z = other.z;
			std::cout << "Coordinates 复制赋值运算符被调用\n";
			return *this;
		}

		Coordinates& operator=(Coordinates&& other) noexcept { // 移动赋值运算符
			if (this == &other)
				return *this;
			x = other.x;
			y = other.y;
			z = other.z;
			new(&arr) (float*)(other.arr);
			other.x = 0.0f;
			other.y = 0.0f;
			other.z = 0.0f;
			other.arr = nullptr;
			std::cout << "Coordinates 移动赋值运算符被调用\n";
			return *this;
		}// 这里是栈区，所以本来是没必要的，只是为了演示堆区的情况（实际还需要有 delete）

		Coordinates(Coordinates&& other) noexcept
			: x(other.x), y(other.y), z(other.z) {
			new(&arr) (float*)(other.arr);
			other.x = 0.0f;
			other.y = 0.0f;
			other.z = 0.0f;
			other.arr = nullptr;
			std::cout << "Coordinates 移动构造函数被调用\n";
		} // 根据微软官方解释：声明移动构造函数或者移动赋值操作符，必须同时显示声明复制构造函数以及显示声明复制赋值运算符。否则编译器默认删除这两个函数的复制语义，导致 C2280 错误

		~Coordinates() {
			delete arr;
			std::cout << "Coordinates 析构函数被调用\n";
		}
	} coord;

	template<typename Ty>
	void print_my_vector(const self::MyVector<Ty>& vec) {
		for (size_t i = 0; i < vec.get_len(); ++i)
			std::cout << vec[i] << "   ";
		std::cout << std::endl;
	}
}

//template<> // 特化版本，打印 coord 类型，这里使用空模版是为了保证参数 coord 完整性
void print_my_vector(const self::MyVector<self::coord>& vec) {
	for (size_t i = 0; i < vec.get_len(); ++i)
		std::cout << "coord: (" << vec[i].x << ", " << vec[i].y << ", " << vec[i].z << ")  ";
	std::cout << std::endl;
	std::cout << "---------------------------------------------------------\n";
}

//void print_my_vector(const std::vector<coord>& vec) {
//	for (size_t i = 0; i < vec.size(); ++i)
//		std::cout << "coord: (" << vec[i].x << ", " << vec[i].y << ", " << vec[i].z << ")  ";
//	std::cout << std::endl;
//	std::cout << "---------------------------------------------------------\n";
//}
